package org.ghost.springboot2.demo.controller;

import com.fasterxml.jackson.core.type.TypeReference;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.ghost.springboot2.demo.common.component.ParameterizedTypeImpl;
import org.ghost.springboot2.demo.component.redis.RedisCacheUtil;
import org.ghost.springboot2.demo.dto.RspDTO;
import org.ghost.springboot2.demo.dto.weather.WeatherForecastDTO;
import org.ghost.springboot2.demo.util.CacheUtil;
import org.ghost.springboot2.demo.util.JacksonUtil;
import org.ghost.springboot2.demo.util.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Type;
import java.util.*;

@RestController
@RequestMapping(value = "demo1")
public class Demo1Controller extends BaseController {
    private final static Logger logger = LoggerFactory.getLogger(Demo1Controller.class);

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @ApiOperation(value = "测试set,get,delete字符型", notes = "测试set,get,delete字符型")
    @RequestMapping(value = "test1", method = RequestMethod.POST)
    public RspDTO test1(@RequestParam String key, @RequestParam String value, @RequestParam int second) {
        redisCacheUtil.set(key, value, second);
        logger.info("获取数据:" + redisCacheUtil.get(key, String.class));

        Object newValue = redisCacheUtil.get(key);
        logger.info("获取数据:" + newValue);

        redisCacheUtil.del(key);
        logger.info("delete后获取数据:" + redisCacheUtil.get(key, String.class));

        return this.render();
    }

    @ApiOperation(value = "测试set,get,delete数字型", notes = "测试set,get,delete数字型")
    @RequestMapping(value = "test2", method = RequestMethod.POST)
    public RspDTO test1(@RequestParam String key, @RequestParam Integer value, @RequestParam int second) {
        redisCacheUtil.set(key, value, second);
        logger.info("获取数据:" + redisCacheUtil.get(key, Integer.class));

        Object newValue = redisCacheUtil.get(key);
        logger.info("获取数据:" + newValue);

        redisCacheUtil.del(key);
        logger.info("delete后获取数据:" + redisCacheUtil.get(key, Integer.class));

        return this.render();
    }

    @ApiOperation(value = "测试set,get,delete复杂类型", notes = "测试set,get,delete复杂类型")
    @RequestMapping(value = "test3", method = RequestMethod.POST)
    public RspDTO test3(@RequestParam String key, @RequestParam int second) {
        WeatherForecastDTO value = new WeatherForecastDTO() {{
            setPm10(123456);
            setPm25(89);
            setQuality("良好");
            setShiDu("重度");
        }};
        redisCacheUtil.set(key, value, second);
        logger.info("获取数据:" + redisCacheUtil.get(key, WeatherForecastDTO.class));

        WeatherForecastDTO newValue = redisCacheUtil.get(key, WeatherForecastDTO.class);
        logger.info("获取数据:" + newValue);

        redisCacheUtil.del(key);
        logger.info("delete后获取数据:" + redisCacheUtil.get(key, WeatherForecastDTO.class));

        return this.render();
    }

    @ApiOperation(value = "测试set,get,delete复杂List类型", notes = "测试set,get,delete复杂List类型")
    @RequestMapping(value = "test4", method = RequestMethod.POST)
    public RspDTO test4(@RequestParam String key, @RequestParam int second) {
        WeatherForecastDTO value = new WeatherForecastDTO() {{
            setPm10(1256);
            setPm25(20);
            setQuality("优秀");
            setShiDu("轻度");
        }};
        redisCacheUtil.set(key, Collections.singleton(value), second);

        List<WeatherForecastDTO> newValue = redisCacheUtil.get(key, List.class, null, WeatherForecastDTO.class);
        logger.info("获取数据:" + newValue);

        newValue = redisCacheUtil.get(key);
        logger.info("获取数据:" + newValue);

        redisCacheUtil.del(key);
        logger.info("delete后获取数据:" + redisCacheUtil.get(key));

        return this.render();
    }

    @ApiOperation(value = "测试zset类型", notes = "测试zset类型")
    @RequestMapping(value = "test5", method = RequestMethod.POST)
    public RspDTO test5(@RequestParam String key, @RequestParam int second) {
        redisCacheUtil.zsetAdd(key, 1, 98);
        redisCacheUtil.zsetAdd(key, 2, 65);
        redisCacheUtil.zsetAdd(key, 3, 100);
        redisCacheUtil.zsetAdd(key, 4, 58);
        redisCacheUtil.zsetAdd(key, 5, 75);
        redisCacheUtil.zsetAdd(key, 6, 47);
        redisCacheUtil.zsetAdd(key, 7, 89);
        redisCacheUtil.zsetAdd(key, 8, 77);
        redisCacheUtil.zsetAdd(key, 9, 90);
        redisCacheUtil.zsetAdd(key, 10, 92);
        redisCacheUtil.zsetAdd(key, 11, 95);
        redisCacheUtil.zsetAdd(key, 12, 94);
        redisCacheUtil.zsetAdd(key, 13, 90);

        logger.info("zsetCard->{}", redisCacheUtil.zsetCard(key));
        logger.info("zsetCount[90,100]->{}", redisCacheUtil.zsetCount(key, 90, 100));
        logger.info("zsetRank[2]->{}", redisCacheUtil.zsetRank(key, 2));
        logger.info("zsetRank[3]->{}", redisCacheUtil.zsetRank(key, 3));
        Set<Long> setUser = redisCacheUtil.zsetRangeByScore(key, 60, 80, 0, 2, Long.class);
        if (CollectionUtils.isNotEmpty(setUser)) {
            logger.info("zsetRangeByScore[60,80,0,2]->{}", setUser.stream().filter(Objects::nonNull).map(String::valueOf).reduce((a, b) -> a + "," + b));
        } else {
            logger.info("zsetRangeByScore[60,80,0,2]->{}", "无数据");
        }

        Set<ZSetOperations.TypedTuple<Integer>> set = redisCacheUtil.zsetRangeByScoreWithScores(key, 90, 100, Integer.class);
        if (CollectionUtils.isNotEmpty(set)) {
            logger.info("zsetRangeByScoreWithScores[90,100]->{}", set.stream().filter(Objects::nonNull).map(it -> it.getValue() + "->" + it.getScore()).reduce((a, b) -> a + ";" + b));
        } else {
            logger.info("zsetRangeByScoreWithScores[90,100]->{}", "无数据");
        }

        redisCacheUtil.del(key);
        logger.info("delete后获取数量:" + redisCacheUtil.zsetCard(key));

        return this.render();
    }

    @ApiOperation(value = "测试List<Map<String,Integet>>等超级复杂类型", notes = "测试List<Map<String,Integet>>等超级复杂类型")
    @RequestMapping(value = "test6", method = RequestMethod.POST)
    public RspDTO test6(@RequestParam String key, @RequestParam int second) {
        Type listType = ParameterizedTypeImpl.make(List.class, new Type[]{Long.class}, null);
        Type mapType = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, listType}, null);
        CacheUtil.getOrSet(redisCacheUtil, key, second,
                new TypeReference<Map<String, List<Long>>>() {
                    @Override
                    public Type getType() {
                        return mapType;
                    }
                },
                () -> {
                    Map<String, List<Long>> rtnMap = new HashMap<String, List<Long>>();
                    rtnMap.put("Hello", Arrays.asList(1L, 254L, 55L));
                    rtnMap.put("World", Arrays.asList(110L, 887L, 444L));
                    return rtnMap;
                });
        logger.info("Map<String, List<Long>>数据:" + JacksonUtil.useDefaultMapper().toJson(redisCacheUtil.get(key, new TypeReference<Map<String, List<Long>>>() {
            @Override
            public Type getType() {
                return mapType;
            }
        })));
        redisCacheUtil.del(key);

        List<Map<String, Map<Long, Double>>> listMap = CacheUtil.getOrSetList(redisCacheUtil, key, second,
                new TypeReference<Map<String, Map<Long, Double>>>() {
                    @Override
                    public Type getType() {
                        return ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, ParameterizedTypeImpl.make(Map.class, new Type[]{Long.class, Double.class}, null)}, null);
                    }
                },
                () -> {
                    List<Map<String, Map<Long, Double>>> rtnList = new ArrayList<Map<String, Map<Long, Double>>>();
                    Map<String, Map<Long, Double>> map1 = new HashMap<String, Map<Long, Double>>();
                    map1.put("Hello", MapUtils.newHashMap(3315555L, 92.0));
                    map1.put("World", MapUtils.newHashMap(3615556L, 88.0));
                    rtnList.add(map1);

                    Map<String, Map<Long, Double>> map2 = new HashMap<String, Map<Long, Double>>();
                    map2.put("测试", MapUtils.newHashMap(2915557L, 73.0));
                    map2.put("数据", MapUtils.newHashMap(6515558L, 69.0));
                    rtnList.add(map2);

                    return rtnList;
                });
        logger.info("List<Map<String, Map<Long, Double>>>数据:" + JacksonUtil.useDefaultMapper().toJson(redisCacheUtil.get(key, new TypeReference<List<Map<String, Map<Long, Double>>>>() {
            @Override
            public Type getType() {
                return ParameterizedTypeImpl.make(List.class, new Type[]{ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, ParameterizedTypeImpl.make(Map.class, new Type[]{Long.class, Double.class}, null)}, null)}, null);
            }
        })));
        redisCacheUtil.del(key);

        return this.render();
    }

    @ApiOperation(value = "测试mset,mget,msetnx类型", notes = "测试mset,mget,msetnx类型")
    @RequestMapping(value = "test7", method = RequestMethod.POST)
    public RspDTO test7(@RequestParam int second) {
        redisCacheUtil.mset("name", "张三", "age", "10", "sex", "男");
        logger.info("获取数据:" + String.join(",", redisCacheUtil.mget("name", "age", "sex")));

        redisCacheUtil.msetnx("name", "李四", "age", "20", "sex", "男");
        logger.info("获取数据:" + String.join(",", redisCacheUtil.mget("name", "age", "sex")));

        redisCacheUtil.del("name");
        logger.info("删除name字段获取数据:" + String.join(",", redisCacheUtil.mget("name", "age", "sex")));

        redisCacheUtil.del("age");
        redisCacheUtil.del("sex");
        logger.info("删除age,sex获取数据:" + String.join(",", redisCacheUtil.mget("name", "age", "sex")));

        return this.render();
    }

    @ApiOperation(value = "测试hset,hget,hdel类型", notes = "测试hset,hget,hdel类型")
    @RequestMapping(value = "test8", method = RequestMethod.POST)
    public RspDTO test8(@RequestParam String key, @RequestParam int second) {
        redisCacheUtil.hset(key, "name", "张三", second);
        redisCacheUtil.hset(key, "age", "10岁", second);
        redisCacheUtil.hset(key, "sex", "男", second);

        logger.info("获取数据长度:" + redisCacheUtil.hlen(key));
        logger.info("获取数据name:" + redisCacheUtil.hget(key, "name", String.class));
        logger.info("获取数据age:" + redisCacheUtil.hget(key, "age", String.class));
        logger.info("获取数据sex:" + redisCacheUtil.hget(key, "sex", String.class));

        redisCacheUtil.hset(key, "name", "西门吹雪", second);
        logger.info("获取数据:" + String.join(",", redisCacheUtil.hgetAllToList(key, String.class)));
        logger.info("获取数据:" + JacksonUtil.useDefaultMapper().toJson(redisCacheUtil.hgetAllToMap(key, String.class)));

        redisCacheUtil.hdel(key, "name");
        logger.info("删除name字段获取数据:" + JacksonUtil.useDefaultMapper().toJson(redisCacheUtil.hgetAllToMap(key, String.class)));

        redisCacheUtil.hdel(key, "age");
        redisCacheUtil.hdel(key, "sex");
        logger.info("删除age,sex获取数据:" + JacksonUtil.useDefaultMapper().toJson(redisCacheUtil.hgetAllToMap(key, String.class)));

        return this.render();
    }

    @ApiOperation(value = "测试lpush,rpush类型", notes = "测试lpush,rpush类型")
    @RequestMapping(value = "test9", method = RequestMethod.POST)
    public RspDTO test9(@RequestParam String key, @RequestParam int second) {
        redisCacheUtil.lpush(key, Arrays.asList("西门吹雪", "叶孤城", "凌凌漆", "零零发"), second);
        redisCacheUtil.rpush(key, Arrays.asList("长江", "黄河", "亚马逊河", "尼罗河"), second);

        logger.info("获取数据长度:" + redisCacheUtil.llen(key));
        logger.info("获取数据lrange:" + String.join(",", redisCacheUtil.lrange(key, 3, 5, String.class)));
        logger.info("获取数据lpop:" + redisCacheUtil.lpop(key, String.class));
        logger.info("获取数据rpop:" + redisCacheUtil.rpop(key, String.class));

        redisCacheUtil.del(key);
        logger.info("删除后获取数据长度:" + redisCacheUtil.llen(key));

        return this.render();
    }
}

